﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Web.Mvc;
using Vit.Common.Helpers;
using Vit.Web.Mvc.DataAnnotations;
using Vit.Web.Providers;

namespace Vit.Web.Mvc
{
    public class AdditionalModelMetadataProvider : DataAnnotationsModelMetadataProvider
    {
        protected override ModelMetadata CreateMetadata(IEnumerable<Attribute> attributes, Type containerType, Func<object> modelAccessor, Type modelType, string propertyName)
        {
            ModelMetadata meta = base.CreateMetadata(attributes, containerType, modelAccessor, modelType, propertyName);
            meta.IsRequired = attributes.Any(x => x is RequiredAttribute || x is KeyAttribute);

            ShowForAttribute showForAttribute = attributes.FirstOrDefault(x => x is ShowForAttribute) as ShowForAttribute;
            if (showForAttribute != null)
            {
                meta.ShowForDisplay = showForAttribute.ShowForDetail;
                meta.ShowForEdit = showForAttribute.ShowForEdit;
            } 

            UIHintAttribute uiHintAttribute = attributes.FirstOrDefault(x => x is UIHintAttribute) as UIHintAttribute;
            if (uiHintAttribute != null && uiHintAttribute.ControlParameters != null)
                meta.AdditionalValues.Add("UIHintParameters", uiHintAttribute.ControlParameters);

            FilterUIHintAttribute fuiHintAttribute = attributes.FirstOrDefault(x => x is FilterUIHintAttribute) as FilterUIHintAttribute;
            if (fuiHintAttribute != null)
            {
                meta.AdditionalValues.Add("FilterUIHint", fuiHintAttribute);
                if (fuiHintAttribute.ControlParameters != null)
                    meta.AdditionalValues.Add("FilterUIHintParameters", fuiHintAttribute.ControlParameters);
            }

            if (containerType != null && containerType.Module.FullyQualifiedName == "<In Memory Module>")
                containerType = containerType.BaseType;

            if (modelType != null && modelType.Module.FullyQualifiedName == "<In Memory Module>")
                modelType = modelType.BaseType;

            DisplayNameAttribute nameAttr = attributes.FirstOrDefault(x => x is DisplayNameAttribute) as DisplayNameAttribute;
            if (nameAttr != null)
            {
                string localizedName = Locale.GetString(containerType, nameAttr.DisplayName);
                meta.DisplayName = string.IsNullOrWhiteSpace(localizedName) ? nameAttr.DisplayName : localizedName;
            }
            else if (containerType != null && !string.IsNullOrWhiteSpace(propertyName))
            {
                string resName = string.Format("{0}_{1}", containerType.Name, propertyName);
                string localizedName = Locale.GetString(containerType, resName); 
                meta.DisplayName = string.IsNullOrWhiteSpace(localizedName) ? propertyName : localizedName;
            }
            else if (modelType != null && containerType == null && string.IsNullOrWhiteSpace(propertyName) && !modelType.FullName.StartsWith("System"))
            {
                string resName = modelType.Name;
                string localizedName = Locale.GetString(modelType, resName); 
                meta.DisplayName = string.IsNullOrWhiteSpace(localizedName) ? modelType.Name : localizedName;
            }

            var validationAttrs = attributes.OfType<ValidationAttribute>();
            if (validationAttrs != null)
            {
                foreach (var attr in validationAttrs)
                {
                    if (!string.IsNullOrWhiteSpace(attr.ErrorMessage))
                    {
                        attr.ErrorMessage = Locale.GetString(containerType, attr.ErrorMessage);
                    }
                }
            }

            var additionalAttrs = attributes.OfType<AdditionalAttribute>();
            if (additionalAttrs != null)
            {
                foreach (var attr in additionalAttrs)
                {
                    meta.AdditionalValues.Add(attr.AddtionalKey, attr);
                }
            }
            return meta;
        }
    }
}
